package com.zeratul.web.advice;

import cn.hutool.core.util.ObjectUtil;
import com.zeratul.common.core.exception.ServiceException;
import com.zeratul.common.core.result.R;
import com.zeratul.common.core.result.codes.ResultCodes;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 自定义异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 全局异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R<?> globalExceptionHandler(Exception e) {
        log.error("【全局异常处理】捕获到全局异常: {}", e.getMessage(), e);
        return R.fail(ResultCodes.FAIL);
    }

    /**
     * 自定义业务异常处理器
     */
    @ExceptionHandler(ServiceException.class)
    public R<?> serviceExceptionHandler(ServiceException e) {
        //将业务异常转换成R对象返回
        return R.fail(e.getCode(), e.getMsg(), e.getData());
    }

    /**
     * 问号传参参数异常处理
     */
    @ExceptionHandler(HandlerMethodValidationException.class)
    public R<?> handlerMethodValidationExceptionHandler(HandlerMethodValidationException e) {
        Map<String, String> errors = new HashMap<>();
        //处理异常信息
        e.getValueResults().forEach(valueResult ->
                valueResult.getResolvableErrors().forEach(v -> {
                    //异常的信息
                    String errorInfo = v.getDefaultMessage();
                    //异常的属性
                    Object[] arguments = v.getArguments();
                    String key = "default";
                    if (ObjectUtil.isNotEmpty(arguments) && arguments[0] instanceof DefaultMessageSourceResolvable dmsr) {
                        key = dmsr.getDefaultMessage();
                    }
                    errors.put(key, errorInfo);
                }));
        return R.fail(ResultCodes.PARAM_ERROR, errors);
    }

    /**
     * 传参实体类异常处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<?> handlerMethodValidationExceptionHandler(MethodArgumentNotValidException e) {
        Map<String, String> allErrors = new HashMap<>();

        //对象上的异常抛出
        Map<String, String> objectErrors = e.getGlobalErrors().stream().collect(Collectors.toMap(
                ObjectError::getObjectName,
                ObjectError::getDefaultMessage,
                (a, b) -> a
        ));
        allErrors.putAll(objectErrors);

        //参数上的异常抛出
        Map<String, String> fieldErrors = e.getFieldErrors().stream().collect(Collectors.toMap(
                FieldError::getField,
                FieldError::getDefaultMessage,
                (a, b) -> a
        ));
        allErrors.putAll(fieldErrors);
        return R.fail(ResultCodes.PARAM_ERROR, allErrors);
    }
}
